local listener = PlayerAuras;

local defaultSettings = {
    isAnnouncing = true,
};

for unit in pairs(PlayerAuras.units) do
    local suffix = unit == "player" and "" or "-" .. unit;
    
    defaultSettings["buffsName" .. suffix] = "Buffs";
    defaultSettings["blocked-Buffs" .. suffix] = {};
    defaultSettings["userAnchors-Buffs" .. suffix] = {};
    defaultSettings["standardAnnounce-Buffs" .. suffix] = "My %s will expire in %d.";
    defaultSettings["noDurationAnnounce-Buffs" .. suffix] = "I have the %s buff.";
    defaultSettings["standardSetting-Buffs" .. suffix] = nil;
    defaultSettings["noDurSetting-Buffs" .. suffix] = nil;
    defaultSettings["debuffsName" .. suffix] = "Debuffs";
    defaultSettings["blocked-Debuffs" .. suffix] = {};
    defaultSettings["userAnchors-Debuffs" .. suffix] = {};
    defaultSettings["standardAnnounce-Debuffs" .. suffix] = "My %s will expire in %d.";
    defaultSettings["noDurationAnnounce-Debuffs" .. suffix] = "I'm afflicted by the %s debuff.";
    defaultSettings["standardSetting-Debuffs" .. suffix] = nil;
    defaultSettings["noDurSetting-Debuffs" .. suffix] = nil;
    defaultSettings["timerSetting-Magic" .. suffix] = nil;
    defaultSettings["timerSetting-Poison" .. suffix] = nil;
    defaultSettings["timerSetting-Disease" .. suffix] = nil;
    defaultSettings["timerSetting-Curse" .. suffix] = nil;
    defaultSettings["timerSetting-Physical" .. suffix] = nil;
end

function listener:FindAnchor(name, target, duration, suffix)
    name = string.lower(name);
    local default, noDurLoc;
    for anchor, settings in pairs(self:Get("userAnchors-" .. target .. suffix)) do
        if duration == nil and settings.noDurLoc then
            noDurLoc = anchor;
        end
        if settings.timers then
            for entry in pairs(settings.timers) do
                if string.find(name, entry) then
                    return anchor;
                end
            end
        end
        if settings.default then default = anchor; end
    end
    
    return noDurLoc or default;
end

function listener:FindTimerSettings(name, anchor, target, duration, type, suffix)
    name = string.lower(name);
    local settings = self:Get("userAnchors-" .. target .. suffix, anchor);
    if settings.timerSettings then
        for setting, entries in pairs(settings.timerSettings) do
            for entry in pairs(entries) do
                if string.find(name, entry) then
                    return setting;
                end
            end
        end
    end
    if type then
        local setting = self:Get("timerSetting-" .. type .. suffix);
        if setting then
            return setting;
        end
    end
    local setting = "standardSetting-" .. target .. suffix;
    if not duration then
        setting = "noDurSetting-" .. target .. suffix;
    end
    return self:Get(setting);
end

function listener:MakeTimer(target, timer)
    --print(target.unit, target.name, timer.name);
    local suffix = target.unit == "player" and "" or "-" .. target.unit;
    local anchor = self:FindAnchor(timer.name, target.name, timer.duration, suffix);
    local timerSettings;
    if timer.module == self then
        timerSettings = self:FindTimerSettings(timer.name, anchor, target.name, timer.duration, timer.debuffType, suffix);
    else
        timerSettings = timer.module.GetTimerSettings and timer.module:GetTimerSettings(self, timer.name) or nil;
    end
    local isHidden = timer.module == self and self:Get("blocked-" .. target.name .. suffix, string.lower(timer.name));
    local priority = timer.module == self and 0 or 10;
    local group = target.name == "Buffs" and self:Get("buffsName" .. suffix) or self:Get("debuffsName" .. suffix);
    local tID = TimerLib:NewTimer(timer, group, timer.module, timerSettings, priority, isHidden, anchor, 10, nil);
    timer.id = tID;
end

function listener:RemoveTimer(target, timer)
    TimerLib:DeleteTimer(timer.id, timer, (timer.module ~= self));
end

function listener:UpdateTimerData(timer)
    local updated = TimerLib:UpdateTimer(timer.id, timer);
    if updated then
        if timer.nameChanged then
            timer.nameChanged = false;
            self:UpdateAnchor(timer);
        end
    else
        -- stupid blizzard's stupid temp enchant code causing stupid problems
        if timer.type == "tempEnchant" then
            self:ClearTempEnchantTimer(timer);
        end
    end
end

listener:SetScript("OnTimerEnter", function(self, target, timer, id, frame)
    if not timer then return; end
    local point = "ANCHOR_RIGHT";
    local counter = 5;
    repeat
        target = timer.target;
        local filter = target.name == "Buffs" and "HELPFUL" or "HARMFUL";
        Ash_GameTooltip:SetOwner(frame, point);
        Ash_GameTooltip:ClearLines();
        local time = GetTime();
        
        if timer.type == "tempEnchant" then
            Ash_GameTooltip:SetInventoryItem("player", timer.weapID);
        elseif timer.type == "tracking" then
            Ash_GameTooltip:SetTracking(timer.trackID);
        elseif timer.type == "stance" then
            Ash_GameTooltip:SetShapeshift(timer.stanceID);
        else
            Ash_GameTooltip:SetUnitAura(target.unit, timer.buffID, filter);
        end
        Ash_GameTooltip:AddLine(" ");
        
        Ash_GameTooltip:AddLine(string.format("|cff00ff00%s|r", timer.name));
        if timer.duration then
            Ash_GameTooltip:AddLine("Remaining: |cff6666ff" .. id:FormatTime(timer.duration - time + timer.time));
        end
        
        Ash_GameTooltip:AddLine(" ");
        Ash_GameTooltip:AddLine("|cffffffff" .. listener:GetKeyBinding("Timer", "Announce") .. "|r to announce.");
        Ash_GameTooltip:AddLine("|cffffffff" .. listener:GetKeyBinding("Timer", "Remove") .. "|r to remove.");
        Ash_GameTooltip:AddLine("|cffffffff" .. listener:GetKeyBinding("Timer", "Block") .. "|r to block.");
        
        Ash_GameTooltip:Show();
        if Ash_GameTooltip:GetWidth() >= UIParent:GetRight() - frame:GetRight() then
            if point == "ANCHOR_LEFT" then
                break;
            else
                point = "ANCHOR_LEFT";
            end
        else   
            break;
        end
        counter = counter - 1;
    until counter <= 0;
    if (counter <= 0) then print("PA fail"); end
end)

listener:SetScript("OnTimerLeave", function(self, target, timer, id, frame)
    Ash_GameTooltip:Hide();
end)

listener:SetScript("OnTimerClick",function(self, target, timer, id, button)
    if timer then
        listener:ProcessClick("Timer", button, timer, id, timer.target);
    else
        TimerLib:DeleteTimer(id, timer, 1);
    end
end)
listener:SetClickAction("Timer", "Remove", function(timer, id)
    if timer.type == "tempEnchant" then
        CancelItemTempEnchantment(timer.weapID - 15);
    elseif timer.type == "tracking" then
        SetTracking(nil);
    elseif timer.type == "stance" then
        -- can't cancel stances, silly!
    elseif UnitIsUnit(timer.target.unit, "player") then
        CancelUnitBuff("player", timer.buffID, timer.filter);
    end
end)
listener:SetClickAction("Timer", "Block", function(timer, _, target)
    if timer then
        local frame = StaticPopup_Show("PLAYERAURAS", timer.name)
        frame.data = timer.name;
        frame.data2 = target.name .. (target.unit == "player" and "" or "-" .. target.unit);
    end
end)
local subTimer, subID;
local subFunc = function(a)
    if a == "%s" then
        return subTimer.name;
    elseif a == "%d" then
        return subTimer.duration and subID:FormatTime(subTimer.duration - GetTime() + subTimer.time) or "";
    else
        return "";
    end
end
listener:SetClickAction("Timer", "Announce", function(timer, id, target)
    if listener:Get("isAnnouncing") then
        local prefix = timer.duration and "standardAnnounce-" or "noDurationAnnounce-";
        local suffix = target.name .. (target.unit == "player" and "" or "-" .. target.unit);
        local subStr = listener:Get(prefix .. suffix);
        subTimer, subID = timer, id;
        local msg = string.gsub(subStr, "(%%%a)", subFunc);
        local loc = GetNumRaidMembers() > 0 and "RAID" or GetNumPartyMembers() > 0 and "PARTY" or "SAY";
        SendChatMessage(msg, loc);
    end
end)
StaticPopupDialogs["PLAYERAURAS"] = {
    text = "Are you sure you want to block |cff00ff00%s|r?  This can be undone from the options panel.",
    button1 = "Yes",
    button2 = "No",
    OnAccept = function(self, name, target) listener:Set("blocked-" .. target, string.lower(name), 1); end,
    whileDead = 1,
    hideOnEscape = 1,
    timeout = 0,
}

function listener:UpdateAnchor(timer)
    local name = timer.target.name;
    local suffix = timer.target.unit == "player" and "" or "-" .. timer.target.unit;
    local anchor = self:FindAnchor(timer.name, name, timer.duration, suffix);
    local timerSettings = self:FindTimerSettings(timer.name, anchor, name, timer.duration, timer.debuffType, suffix);
    local isHidden = timer.module == self and self:Get("blocked-" .. name .. suffix, string.lower(timer.name));
    local priority = timer.module == self and 0 or 10;
    TimerLib:UpdateTimerInfo(timer.id, timer, priority, isHidden, timerSettings);
    local group = name == "Buffs" and self:Get("buffsName" .. suffix) or self:Get("debuffsName" .. suffix);
    TimerLib:MoveTimer(timer.id, timer, group, anchor, 10, nil);
end

listener:AddDefaultSettings(defaultSettings);
listener:AddSettingsUpdateScript(function(self)
    if self:GetUserSet("keybindings") == nil then
        self:Set("keybindings", {
            ["Timer"] = {
                ["Announce"] = "1",
                ["Remove"] = "2",
                ["Block"] = "s-2",
            },
        });
    end
    for unit in pairs(self.units) do
        local suffix = unit == "player" and "" or "-" .. unit;
        if not self:GetUserSet("userAnchors-Buffs" .. suffix) then
            self:Set("userAnchors-Buffs" .. suffix, {
                ["PlayerAuras Anchor" ..suffix] = {
                    default = true,
                    timers = {},
                    timerSettings = {},
                },
            });
        end
        if not self:GetUserSet("userAnchors-Debuffs" .. suffix) then
            self:Set("userAnchors-Debuffs" .. suffix, {
                ["PlayerAuras Anchor" .. suffix] = {
                    default = true,
                    timers = {},
                    timerSettings = {},
                },
            });
        end
    end
    if self:Get("enabled") and not AsheylaLib:InSimpleMode() then
        self:RegisterEvent("PLAYERAURAS_NEW_TIMER", self.MakeTimer);
        self:RegisterEvent("PLAYERAURAS_DONE_TIMER", self.RemoveTimer);
        self:RegisterEvent("PLAYERAURAS_UPDATE_TIMERDATA", self.UpdateTimerData);
        
        for unit, filters in pairs(self.units) do
            for name, target in pairs(filters) do
                for timer in target:GetTimers() do
                    self:UpdateAnchor(timer);
                end
            end
        end
    else
        self:UnregisterEvent("PLAYERAURAS_NEW_TIMER");
        self:UnregisterEvent("PLAYERAURAS_DONE_TIMER");
        self:UnregisterEvent("PLAYERAURAS_UPDATE_TIMERDATA");
        TimerLib:DeleteAllTimers(self);
    end
end);

TimerLib:AddSettingsUpdateScript(function(self)
    if not self:GetUserSet("timerSettings", "PlayerAuras Timer") then
        self:Set("timerSettings", "PlayerAuras Timer", {});
    end
    
    for unit in pairs(PlayerAuras.units) do
        local suffix = unit == "player" and "" or "-" .. unit;
        if not self:GetUserSet("anchorSettings", "PlayerAuras Anchor" .. suffix) then
            self:Set("anchorSettings", "PlayerAuras Anchor" .. suffix, {
                groupSortMethod = "Alphabetical (A)",
                defaultTimerSetting = "PlayerAuras Timer",
            });
        end
        
        local default;
        for name, settings in pairs(PlayerAuras:Get("userAnchors-Buffs" .. suffix)) do
            if not self:Get("anchorSettings", name) then
                PlayerAuras:Set("userAnchors-Buffs" .. suffix, name, nil);
            elseif settings.default then
                default = name;
            end
        end
        if not default then
            PlayerAuras:Set("userAnchors-Buffs" .. suffix, "PlayerAuras Anchor", "default", true);
        end
        
        default = nil;
        for name, settings in pairs(PlayerAuras:Get("userAnchors-Debuffs" .. suffix)) do
            if not self:Get("anchorSettings", name) then
                PlayerAuras:Set("userAnchors-Debuffs" .. suffix, name, nil);
            elseif settings.default then
                default = name;
            end
        end
        if not default then
            PlayerAuras:Set("userAnchors-Debuffs" .. suffix, "PlayerAuras Anchor", "default", true);
        end
    end
end);
